/*===========================================================================
  Copyright (C) 2014 by the Okapi Framework contributors
-----------------------------------------------------------------------------
  This library is free software; you can redistribute it and/or modify it 
  under the terms of the GNU Lesser General Public License as published by 
  the Free Software Foundation; either version 2.1 of the License, or (at 
  your option) any later version.

  This library is distributed in the hope that it will be useful, but 
  WITHOUT ANY WARRANTY; without even the implied warranty of 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
  General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License 
  along with this library; if not, write to the Free Software Foundation, 
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

  See also the full LGPL text here: http://www.gnu.org/copyleft/lesser.html
===========================================================================*/

package net.sf.okapi.v2.common.om;

import java.util.List;

import net.sf.okapi.v2.common.exceptions.InvalidPositionException;

/**
 * Represent a fragment of content that can be an inter-segment part or a segment.
 */
public interface ITextFragment extends CharSequence, Appendable {

	/**
	 * Returns a string representation of the fragment: the text in coded text format.
	 * The method has the same effect as calling {@link #getCodedText()}.
	 * @return the coded text for this fragment.
	 */
	public String toString ();
	
	/**
	 * Gets the character at the specified index in the coded text of this fragment.
	 * The character may be a special character used in a tag reference.
	 * @return the specified character.
	 * @throws IndexOutOfBoundsException if the if the index is out of bounds.
	 */
	public char charAt (int index);
	
	/**
	 * Gets the number of character in the coded text of this fragment.
	 * <p>This is not the length of the content with all its codes expanded.
	 * @return the number of character in the coded text of this fragment.
	 */
	public int length ();

	/**
	 * Gets a copy of a sub-sequence of the coded text this fragment.
	 * Only the coded text is copied. If the coded text has tag references the reference remain 
	 * unchanged and no copy of the referenced objects are made.
	 * @param start the position of the first character or tag reference of the sub-sequence.
	 * @param end the position just after the last character or tag reference of the sub-sequence.
	 * You can use -1 for ending the sub-sequence at the end of the fragment.
	 * @return a sub-sequence of the coded text of this fragment.
	 * @throws InvalidPositionException if the start or end position fall on the second spacial
	 * character of a tag reference.
	 * @throws IndexOutOfBoundsException if the start or end position is out of bounds.
	 * @see #getCodedText()
	 */
	public String subSequence (int start,
		int end);

	/**
	 * Gets the id for this part.
	 * @return the id for this part or null.
	 */
	public String getId ();
	
	/**
	 * Sets the id for this part.
	 * @param id the id to set (can be null).
	 */
	public void setId (String id);
	
	/**
	 * Indicates if this fragment is a segment or not.
	 * @return true if it is a segment, false if not.
	 */
	public boolean isSegment ();
	
	/**
	 * Indicates if this fragment is empty (no text and no tags).
	 * @return true if the fragment is empty, false otherwise.
	 */
	public boolean isEmpty ();

	/**
	 * Indicates if this fragment contains at least one character other than a whitespace.
	 * (inline tags do not count as characters).
	 * @return true if this fragment contains at least one character, excluding whitespace.
	 */
	public boolean hasText ();
	
	/**
	 * Indicates if this fragment contains at least one character
	 * (inline tags do not count as characters).
	 * @param whitespaceIsText indicates if whitespace characters should be considered 
	 * characters or not for the purpose of checking if this fragment is empty.
	 * In this method, a whitespace character is a character return true when 
	 * calling {@link Character#isWhitespace(char)}.
	 * @return true if this fragment contains at least one character (that character could
	 * be a whitespace if whitespaceIsText is set to true).
	 */
	public boolean hasText (boolean whitespaceIsText);

	/**
	 * Gets the coded text for this fragment.
	 * @return the coded text for this fragment.
	 * @see #subSequence(int, int)
	 */
	public String getCodedText ();
	
	/**
	 * Sets the coded text of the fragment, using its the existing tags.
	 * The tag references in the new coded text must be valid for the existing tags.
	 * @param codedText the coded text to apply.
	 */
	public void setCodedText (String codedText);

	/**
	 * Creates a string representing the plain text version (all tag references stripped out) of this fragment.
	 * This is similar to <code>getText()</code> is v1.
	 * @return the plain text version of this fragment.
	 */
	public String getPlainText ();

	/**
	 * Creates a string representing the content of this fragment, including the original codes whenever
	 * possible. Annotations are not represented and hidden protected content is also not represented.
	 * This is the same as <code>toText()</code> is v1.
	 * @return the content of this fragment.
	 */
	public String getText ();
	
	/**
	 * Gets the text container object where this fragment exists.
	 * @return the parent text container of this fragment.
	 */
	ITextContainer getParent ();
	
	/**
	 * Indicates if this fragment has at least one tag reference.
	 * @return true if this fragment has one tag reference or more.
	 */
	public boolean hasTag ();

	/**
	 * Gets the tag collection associated with this fragment.
	 * Note that tags are shared across all fragments, so the returns object is likely to contain tags not used in this fragment.
	 * To get a list of the tags used only in this fragment use {@link #getOwnTags()}.
	 * @return the tag collection associated with this fragment.
	 * @see #getCodedText()
	 * @see #getOwnTags()
	 */
	public ITags getTags ();
	
	/**
	 * Creates a list of the tags that have a reference in this fragment.
	 * The tag are listed in the order they occur in the coded text.
	 * To get the collection of all tags associated with this fragment and the other fragments of
	 * the container use {@link #getTags()}.
	 * @return a new list of the tags that have a reference in this fragment (can be empty but never null).
	 * @see #getTags()
	 */
	public List<ITag> getOwnTags ();

	/**
	 * Clears this fragment of all text and its tags.
	 * The tags objects are also removed.
	 */
	public void clear ();

	/**
	 * Deletes a span of content and any tag that has its reference within that span.
	 * @param start the first character to delete in the coded text.
	 * @param end the position after the last character to delete in the coded text.
	 * You can use -1 to indicate the end of the content.
	 * @throws InvalidPositionException if the start or end parameters are at invalid
	 * position (e.g. they cannot be on the second special character of a tag reference
	 * character pair).
	 */
	public void delete (int start,
		int end);
	
	/**
	 * Appends a character at the end of this fragment.
	 * @param ch the character to append.
	 * @return the fragment itself.
	 */
	public ITextFragment append (char ch);

	/**
	 * Appends a plain text string to this fragment.
	 * If the parameter is null, a string "null" is appended.
	 * @param plainText the string to append.
	 * @return the fragment itself.
	 */
	public ITextFragment append (CharSequence plainText);
	
	/**
	 * Appends a sub-sequence of a given plain text string to this fragment.
	 * If the parameter is null, a string "null" is appended.
	 * @param plainText the source for the sub-sequence to append.
	 * @param start the index of the first character in the subsequence.
	 * @param end the index of the character following the last character in the subsequence.
	 * @return the fragment itself.
	 */
	public ITextFragment append (CharSequence plainText,
		int start,
		int end);
	
	/**
	 * Inserts a code at a given position (including the end) of this fragment.
	 * @param tagType the type of tag of the code.
	 * @param type the type of the code.
	 * @param id the id of the code (if null an new ID is created automatically)
	 * @param data the original data for the code (can be null).
	 * @param offset the position where to insert the code. Use -1 to append. Other negative values or values greater
	 * then the length of the coded text also cause the code to be appended at the end of the fragment.
	 * @param connect true to connect a new opening code to its closing counterpart, or to connect
	 * a new closing code to its opening counterpart (the counterpart may be in a different fragment).
	 * Use false to create new opening or closing codes.
	 * This option is ignored used if the code is standalone.
	 * @param allowOrphan true to allow the connect option to fail, that is: to not found the counterpart
	 * of the new code. this option is ignore if connect is false or if the new code is a standalone code. 
	 * @return the new {@link ICode} created.
	 */
	public ICode insert (TagType tagType,
		String type,
		String id, 
		String data,
		int offset,
		boolean connect,
		boolean allowOrphan);
	
	/**
	 * Creates a new opening or standalone code, or closes an existing opening code at the end of this fragment.
	 * Helper method equivalent to <code>insert(tagType, type, null, data, -1, (tagType==TagType.CLOSING), false)</code>.
	 * @param tagType the type of tag of the code.
	 * @param type the type of the code.
	 * @param data the original data for the code.
	 * @return the new {@link ICode} created.
	 */
	public ICode append (TagType tagType,
		String type, 
		String data);
	
	/**
	 * Appends a standalone code to this fragment.
	 * Helper method equivalent to <code>append(TagType.STANDALONE_CODE, type, null, data, -1, false, false)</code>.
	 * @param type the type of the code.
	 * @param data the original data for the code, e.g. <code>&lt;BR></code>. (can be null). 
	 * @return the new {@link ICode} created.
	 */
	public ICode appendStandaloneCode (String type,
		String data);

	/**
	 * Creates a new opening code at the end of this fragment.
	 * Helper method equivalent to <code>append(TagType.OPENING_CODE, type, null, data, -1, false, false)</code>.
	 * @param type the type of the code.
	 * @param data the original data for the code, e.g. <code>&lt;B></code>. (can be null).
	 * @return the new {@link ICode} created.
	 */
	public ICode openCode (String type, 
		String data);
	
	/**
	 * Closes an existing opening code.
	 * Helper method equivalent to <code>append(TagType.CLOSING_CODE, null, id, data, true, false)</code>.
	 * @param id the id of the code to close.
	 * @param data the original data for the code, e.g. <code>&lt;/B></code>. (can be null).
	 * @return the new {@link ICode} created.
	 */
	public ICode closeCode (String id,
		String data);
	
	/**
	 * Creates a new opening marker at the end of this fragment. 
	 * @param id the id of the marker.
	 * @param type the type of the marker.
	 * @return the new {@link IMarker} created.
	 */
	public IMarker openMarker (String id,
		String type);

	/**
	 * Closes an existing marker.
	 * @param id the id of the marker to close.
	 * @return the new {@link IMarker} created.
	 */
	public IMarker closeMarker (String id);
	
	/**
	 * Inserts a plain text at a given position in the coded text.
	 * @param pos the position where to insert.
	 * @param plainText the string to insert.
	 * @throws InvalidPositionException if the insertion point is inside a tag reference.
	 * @throws StringIndexOutOfBoundsException if the insertion point is out of bounds.
	 */
	public void insert (int pos,
		String plainText);

	/**
	 * Changes a span of the coded text into a single code. Any code already
	 * existing that is within the range is removed to become part of the new code.
	 * There must be no annotation markers or hidden protected content within the span.
	 * @param start The position of the first character or marker of the span
	 * (in the coded text representation).
	 * @param end the position just after the last character or marker of the span
	 * (in the coded text representation). You can use -1 to indicates the end of the fragment.
	 * @param tagType the tag type of the new code.
	 * @param id the id to use (or null to use auto-id).
	 * @return the difference between the coded text length before and after 
	 * the operation. This value can be used to adjust further start and end positions
	 * that have been calculated on the coded text before the changes are applied.
	 * @throws InvalidPositionException when start or end points inside a marker.
	 */
	public int changeToCode (int start,
		int end,
		TagType tagType,
		String id);

}
